/* P2PprotocolCPP.h --- P2PprotocolCPP
 */

#ifndef INCLUDED_P2PPROTOCOLCPP_H
#define INCLUDED_P2PPROTOCOLCPP_H 1


#include <vector>
#include <list>

namespace P2Pprotocol {
    class Channel;
    class PeerPort;
    class SerialPort;
    class UdpPort;
    struct virtual_channel_opts;
    typedef void(*RecvCallbackFuncType)(Channel*, struct data_info_exch*);
    typedef void(*SendCallbackFuncType)(Channel*, struct data_info_exch*);
}

namespace P2PprotocolCPP {

    class P2PChannel;

    typedef void(*SendCallbackForCPPType)(P2PChannel& channel, unsigned char* data, int length);
    typedef void(*RecvCallbackForCPPType)(P2PChannel& channel, unsigned char* data, int length);

    class SerialOptions
    {
    public:
        int baudrate; // B19200, B38400, etc.
        int databits; // CSIZE  Character size mask.  Values are CS5 CS6 CS7 CS8
        int parity; // None=0, Odd=1, Even=2, Mark=3, Space=4
        int stopbits; // 0 or 2 (no 1.5 yet)
        int handshake; // currently, set this to 0

    public:
        SerialOptions();
    };

    class ChannelOptions
    {
    public:
        unsigned short src;
        unsigned short dst;
        unsigned short prtlver; // Supported protocol version
        unsigned long long exever; // Executive version: 6 bytes
        unsigned short appstamp; // Application compatibility stamp
        unsigned short exeidcrc; // Executive ID CRC
        unsigned short appidcrc; // Application ID CRC
        unsigned int vtcrcinit; // Vital CRC Init Value: 3 bytes
        unsigned char vtflag; // Vital data field present vital == 1 non-vital == 2;

        unsigned char obitc; // Vital Boolean output count
        unsigned char oblkc; // Count of Vital numeric output block definitions
        unsigned char obtc; // Count of Vital byte numeric outputs
        unsigned char owdc; // Count of Vital word numeric outputs
        unsigned char odwdc; // Count of Vital long word numeric outputs
        unsigned char ibitc; // Vital Boolean input count
        unsigned char iblkc; // Count of Vital numeric input block definitions
        unsigned char ibtc; // Count of Vital byte numeric inputs
        unsigned char iwdc; // Count of Vital word numeric inputs
        unsigned char idwdc; // Count of Vital word numeric inputs

        // timer related info, in ms
        unsigned int stlto; // Stale Data Timeout
        unsigned int ackto; // Acknowledge Timeo
        unsigned int hbtto; // Heartbeat Interval
        unsigned int induc; // Indication Update Cycle, if 0, never send data
        unsigned int ackdelto; // ack delay defaults to be 100 ms;

        SendCallbackForCPPType data_send_callback;
        RecvCallbackForCPPType data_recv_callback;

        // for upper usage
        void* user_data;
        int channel_status;
#define CHANNEL_STATUS_CONNECTING	1
#define CHANNEL_STATUS_CONNECTED	2
        int peererror;

    public:
        ChannelOptions(unsigned short localPeerAddress, unsigned short remotePeerAddress, unsigned char outputBitsCount, unsigned char inputBitsCount);
    };

    class ComPort
    {
    private:
        P2Pprotocol::SerialPort* port;
        void ComPortInit(const char* portname, SerialOptions& options);
        //void(*pRecvCallback)(P2Pprotocol::Channel channel, P2PChannel::data_info_exch data);

    public:
        ComPort(const char* portname);
        ComPort(const char* portname, SerialOptions options) { ComPortInit(portname, options); };
        P2Pprotocol::SerialPort* getPort() { return port; }
    };

    class UdpPort
    {
    private:
        P2Pprotocol::UdpPort* port;

    public:
        UdpPort(const char* lip, unsigned short lport, const char* rip, unsigned short rport);
        P2Pprotocol::UdpPort* getPort() { return port; }

    };

    class P2PChannel
    {
    private:
        P2Pprotocol::Channel* channel;
        SendCallbackForCPPType sendCallback;
        RecvCallbackForCPPType recvCallback;
        void setOptions(ChannelOptions& opts, P2Pprotocol::virtual_channel_opts* lOpts);
        void P2PChannelInit(ChannelOptions& opts, P2Pprotocol::UdpPort* port);
        void P2PChannelInit(ChannelOptions& opts, P2Pprotocol::SerialPort* port);
        //void(*pRecvCallback)(P2Pprotocol::Channel channel, P2PChannel::data_info_exch data);

    public:
        P2PChannel(ChannelOptions& opts, ComPort& port) { P2PChannelInit(opts, port.getPort()); }
        P2PChannel(ChannelOptions& opts, UdpPort& port) { P2PChannelInit(opts, port.getPort()); }
        unsigned short getSrcId();
        unsigned short getDstId();
        unsigned short getInputBitsCount();
        unsigned short getOutputBitsCount();
        P2Pprotocol::Channel* getChannel() { return channel; }
		void start();
		void stop();
		SendCallbackForCPPType getSendCallback() { return sendCallback; }
        RecvCallbackForCPPType getRecvCallback() { return recvCallback; }
        void TryToSend(std::vector<unsigned char>& data);
        void TryToSend(const unsigned char *data, int length);
        bool isConnected();
    };

    class P2PManager
    {
    public:
        //static const std::list<P2PChannel*> channels = std::list<P2PChannel*>();
        static std::list<P2PChannel*> channels;
        static P2Pprotocol::SendCallbackFuncType sendCallbackForCPP;// = process;
        static P2Pprotocol::RecvCallbackFuncType recvCallbackForCPP;// = process;

        static void setLogFile(const char* logfilename);
        /*level can be:
          "EMERGERNCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"
          If not set, default is "INFO"
        */
        static void setLogLevel(const char *level);
        static void start();
        static void stop();
    };
}

#endif /* INCLUDED_P2PPROTOCOLCPP_H */

